package com.byd.base;

import java.lang.ref.SoftReference;
import java.util.LinkedList;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import com.byd.utils.Lg;

public abstract class BaseFragment extends Fragment implements IPresenter, IUIEvent, IUserAction {
	protected Context mContext;
	private BasePresenter<? extends BaseFragment> mPresenter;
	private SoftReference<View> mCacheView;
	private boolean mAcceptUserAction;
	private boolean mAcceptUIEvent;
	private boolean mParentHidden = false;
	private boolean mStop = false;
	private boolean mReallyHidden = true;
	private final LinkedList<BaseFragment> mChildFragments = new LinkedList<BaseFragment>();
	private final Handler mHandler = new Handler(Looper.getMainLooper());

	public BaseFragment() {
		v("new instance");
	}

	private final String getTagStr() {
		return Lg.BASE_TAG + getClass().getSimpleName();
	}

	protected final void v(Object msg) {
		Lg.v(getTagStr(), msg);
	}

	protected final void d(Object msg) {
		Lg.d(getTagStr(), msg);
	}

	protected final void i(Object msg) {
		Lg.i(getTagStr(), msg);
	}

	protected final void w(Object msg) {
		Lg.w(getTagStr(), msg);
	}

	protected final void e(Object msg) {
		Lg.e(getTagStr(), msg);
	}

	protected final void wtf(Object msg) {
		Lg.wtf(getTagStr(), msg);
	}

	/** 创建Presenter */
	protected abstract BasePresenter<? extends BaseFragment> onCreatePresenter();

	/** 返回布局文件ID */
	protected abstract int onInflateView();

	@Override
	public void onAttach(Activity activity) {
		super.onAttach(activity);
		mContext = activity;
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		View view = getContentView();
		final boolean create = view == null;
		if(create) {
			view = inflater.inflate(onInflateView(), container, false);
			mCacheView = new SoftReference<View>(view);
		}
		onCreate();
		mPresenter = onCreatePresenter();
		if(mPresenter != null) {
			mPresenter.performCreate(mContext, this);
		}
		return view;
	}

	/** View已创建完毕，可在此控制View或注册事件等 */
	protected void onCreate() {
		// nothing
	}

	@Override
	public void onStart() {
		super.onStart();
		mStop = false;
		updateHidden();
		if(mPresenter != null) {
			mPresenter.performStart();
		}
	}

	@Override
	public void onResume() {
		super.onResume();
		if(mPresenter != null) {
			mPresenter.performResume();
		}
	}

	@Override
	public synchronized void onHiddenChanged(boolean hidden) {
		super.onHiddenChanged(hidden);
		updateHidden();
		for (final BaseFragment child : mChildFragments) {
			child.parentHiddenChanged(hidden);
		}
	}

	@Override
	public void onPause() {
		super.onPause();
		if(mPresenter != null) {
			mPresenter.performPause();
		}
	}

	@Override
	public void onStop() {
		super.onStop();
		mStop = true;
		updateHidden();
		if(mPresenter != null) {
			mPresenter.performStop();
		}
	}

	@Override
	public void onDestroy() {
		v("onDestroy");
		super.onDestroy();
		onRelease();
		unregiestUIEvent();
		unregiestUserAction();
		if(mPresenter != null) {
			mPresenter.onDestroy();
		}
		mPresenter = null;
		mChildFragments.clear();
		mHandler.removeCallbacksAndMessages(null);
		mContext = null;
		mCacheView = null;
	}

	/** 替代原{@link #onDestroy} */
	protected void onRelease() {
		// for Override
	}

	@Override
	protected void finalize() throws Throwable {
		i("finalize: " + toString());
		super.finalize();
	}

	final synchronized void parentHiddenChanged(boolean hidden) {
		if(mParentHidden != hidden) {
			mParentHidden = hidden;
			updateHidden();
			for (final BaseFragment child : mChildFragments) {
				child.parentHiddenChanged(hidden);
			}
		}
	}

	private final void updateHidden() {
		final boolean reallyHidden = mParentHidden || isHidden() || mStop;
		if(mReallyHidden != reallyHidden) {
			mReallyHidden = reallyHidden;
			if(mPresenter != null) {
				if(mReallyHidden) {
					mPresenter.performInactive();
				}
				else {
					mPresenter.performActive();
				}
			}
			onReallyHiddenChanged(mReallyHidden);
		}
	}

	/** Fragment是否真正隐藏，如果本身未隐藏，而父Fragment隐藏的话，此Fragment也算是真的隐藏
	 * 
	 * @param hidden */
	protected void onReallyHiddenChanged(boolean hidden) {
		// nothing
	}

	public LinkedList<BaseFragment> getChildFragments() {
		return mChildFragments;
	}

	public synchronized void addFragment(int resId, Class<? extends BaseFragment> cls) {
		try {
			final BaseFragment fragment = cls.newInstance();
			addFragment(resId, fragment);
		}
		catch (final Exception e) {
			Lg.printStackTrace(e);
		}
	}

	public synchronized void addFragment(int resId, BaseFragment fragment) {
		final FragmentManager manager = getFragmentManager();
		final FragmentTransaction transaction = manager.beginTransaction();
		transaction.add(resId, fragment, fragment.getClass().getSimpleName());
		transaction.commit();
		mChildFragments.add(fragment);
	}

	public synchronized void removeFragment(BaseFragment fragment) {
		final FragmentManager manager = getFragmentManager();
		final FragmentTransaction transaction = manager.beginTransaction();
		transaction.remove(fragment);
		transaction.commit();
		mChildFragments.remove(fragment);
	}

	public synchronized void removeAllFragments() {
		final LinkedList<BaseFragment> fragments = mChildFragments;
		if(fragments.size() > 0) {
			final FragmentManager manager = getFragmentManager();
			final FragmentTransaction transaction = manager.beginTransaction();
			while (fragments.size() > 0) {
				transaction.remove(fragments.removeLast());
			}
			transaction.commit();
		}
	}

	/** 注册接收{@link UIEvent} */
	protected final void regiestUIEvent() {
		if(!mAcceptUIEvent) {
			mAcceptUIEvent = true;
			final Activity activity = getActivity();
			if(activity != null && activity instanceof BaseActivity) {
				final BaseActivity baseActivity = (BaseActivity) activity;
				baseActivity.regiesterUIEvent(this);
			}
		}
	}

	/** 反注册{@link UIEvent} */
	protected final void unregiestUIEvent() {
		if(mAcceptUIEvent) {
			mAcceptUIEvent = false;
			final Activity activity = getActivity();
			if(activity != null && activity instanceof BaseActivity) {
				final BaseActivity baseActivity = (BaseActivity) activity;
				baseActivity.unregiesterUIEvent(this);
			}
		}
	}

	@Override
	public void onRecieveUIEvent(UIEvent event) {
		if(mPresenter != null) {
			mPresenter.performUIEvent(event);
		}
	}

	@Override
	public final boolean isAcceptUIEvent() {
		return !mReallyHidden;
	}

	/** 注册接收用户动作：{@link #onBackPressed()}和{@link #onWindowTouchDown(MotionEvent)} */
	protected final void regiestUserAction() {
		if(!mAcceptUserAction) {
			mAcceptUserAction = true;
			final Activity activity = getActivity();
			if(activity != null && activity instanceof BaseActivity) {
				final BaseActivity baseActivity = (BaseActivity) activity;
				baseActivity.regiesterUserAction(this);
			}
		}
	}

	protected final void unregiestUserAction() {
		if(mAcceptUserAction) {
			mAcceptUserAction = false;
			final Activity activity = getActivity();
			if(activity != null && activity instanceof BaseActivity) {
				final BaseActivity baseActivity = (BaseActivity) activity;
				baseActivity.unregiesterUserAction(this);
			}
		}
	}

	@Override
	public boolean onBackPressed() {
		return false;
	}

	@Override
	public boolean onWindowTouchDown(MotionEvent event) {
		return false;
	}

	@Override
	public final boolean isAcceptUserAction() {
		return !mReallyHidden;
	}

	@Override
	public final void sendUIEvent(UIEvent event, Class<?>... filter) {
		final Activity activity = getActivity();
		if(activity != null && activity instanceof IPresenter) {
			final BaseActivity baseActivity = (BaseActivity) activity;
			baseActivity.sendUIEvent(this, event, filter);
		}
	}

	protected final View getContentView() {
		if(mCacheView != null) {
			return mCacheView.get();
		}
		return null;
	}

	protected final void setVisibility(int visibility) {
		final View view = getContentView();
		if(view != null) {
			view.setVisibility(visibility);
		}
	}

	protected final View findViewById(int id) {
		final View view = getContentView();
		if(view != null) {
			return view.findViewById(id);
		}
		return null;
	}

	protected final BasePresenter<? extends BaseFragment> getPresenter() {
		return mPresenter;
	}

	protected final int getColor(int id) {
		return getResources().getColor(id);
	}

	public boolean getBoolean(int id) {
		return getResources().getBoolean(id);
	}

	protected final float getDimension(int id) {
		return getResources().getDimension(id);
	}

	protected final int getDimensionPixelOffset(int id) {
		return getResources().getDimensionPixelOffset(id);
	}

	protected final int getDimensionPixelSize(int id) {
		return getResources().getDimensionPixelSize(id);
	}

	protected final Drawable getDrawable(int id) {
		return getResources().getDrawable(id);
	}

	protected final String[] getStringArray(int id) {
		return getResources().getStringArray(id);
	}

	protected final int getInteger(int id) {
		return getResources().getInteger(id);
	}

	protected final int[] getIntArray(int id) {
		return getResources().getIntArray(id);
	}

	protected final DisplayMetrics getDisplayMetrics() {
		return getResources().getDisplayMetrics();
	}

	protected final Configuration getConfiguration() {
		return getResources().getConfiguration();
	}

	protected final boolean post(Runnable r) {
		return mHandler.post(r);
	}

	protected final boolean postSingle(Runnable r) {
		mHandler.removeCallbacks(r);
		return mHandler.post(r);
	}

	protected final boolean postDelayed(Runnable r, long delayMillis) {
		return mHandler.postDelayed(r, delayMillis);
	}

	protected final boolean postSingleDelayed(Runnable r, long delayMillis) {
		mHandler.removeCallbacks(r);
		return mHandler.postDelayed(r, delayMillis);
	}

	protected final void removeCallbacks(Runnable r) {
		mHandler.removeCallbacks(r);
	}
}
